import pygame
import random
import sys


# 屏幕大小
SCREEN_X = 600
SCREEN_Y = 600


class Snake(object):
    def __init__(self) -> None:
        self.dirction = pygame.K_RIGHT  # 定义初始化蛇头的运行方向
        self.body = []  # 初始化蛇的body，body中存储若干个矩形对象，将蛇分成若干个小矩形
        for i in range(5):
            self.addNode()
        super().__init__()
    
    def addNode(self):
        """蛇头往某个方向移动一个单位"""
        left, top = 0, 0  # 设置初始的坐标点
        if self.body:
            left, top = self.body[0].left, self.body[0].top  # 标记蛇头的坐标
        head = pygame.Rect(left, top, 25, 25)  # 标记一个25*25的区域，该区域为蛇头的显示区域
        if self.dirction == pygame.K_LEFT:
            head.left -= 25  # 向左移动一个小格子
        elif self.dirction == pygame.K_RIGHT:
            head.left += 25  # 向右移动一个小格子
        elif self.dirction == pygame.K_UP:
            head.top -= 25  # 向上移动一个小格子
        elif self.dirction == pygame.K_DOWN:
            head.top += 25  # 向下移动一个小格子
        self.body.insert(0, head)  # 在蛇的body中插入新的蛇头的矩形
    
    def delNode(self):
        """蛇移动后删除原来的最后一节身体"""
        self.body.pop()
        
    def isDead(self):
        """判断蛇是否死亡"""
        # 1.撞墙判断
        if self.body[0].left >= SCREEN_X or self.body[0].left < 0:  # 超过横轴范围
            return True
        if self.body[0].top >= SCREEN_Y or self.body[0].top < 0:  # 超出纵轴范围
            return True
        # 2.撞自己
        if self.body[0] in self.body[1:]:
            return True
        return False
    
    def move(self):
        """蛇的移动，蛇头先往前移动一个单位，再删除原来的蛇尾"""
        self.addNode()
        self.delNode()
        
    def changeDirction(self, curKey):
        """监听键盘事件，改变蛇的运动方向"""
        LR = [pygame.K_LEFT, pygame.K_RIGHT]
        UD = [pygame.K_UP, pygame.K_DOWN]
        if curKey in LR + UD:  # 如果键盘按下的是上下左右四个方向键
            if (curKey in LR) and (self.dirction in LR):  # 如果按下的是左右，且蛇当前的方向就是左右，那么不能改变蛇的方向
                return
            if (curKey in UD) and (self.dirction in UD):  # 同上
                return
            self.dirction = curKey  # 改变蛇的前进方向
            
            
class Food(object):
    def __init__(self) -> None:
        self.rect = pygame.Rect(-25, 0, 25, 25)  # 初始化方格位置
        super().__init__()
        
    def remove(self):
        """重置食物方格"""
        self.rect.left = -25
        
    def set(self):
        """重新放置食物"""
        if self.rect.left == -25:  # 食物处于初始化的状态才重新放置
            all_pos = []
            for pos in range(25, SCREEN_X-25, 25):  # 食物不会贴墙放置
                all_pos.append(pos)
            self.rect.left = random.choice(all_pos)
            self.rect.top = random.choice(all_pos)
            
            
def show_text(screen, pos, text, color, font_bold=False, font_size=60, font_italic=False):
    """向屏幕中添加文字"""
    # 获取系统字体，并设置大小
    cur_font = pygame.font.SysFont("宋体", font_size)
    # 设置是否加粗
    cur_font.set_bold(font_bold)
    # 设置是否斜体
    cur_font.set_italic(font_italic)
    # 设置文字内容
    text_fmt = cur_font.render(text, 1, color)
    # 绘制文字
    screen.blit(text_fmt, pos)
            


def main():
    # 1.游戏模块初始化
    pygame.init()
    screen_size = (SCREEN_X, SCREEN_Y)
    # 2.画出界面
    screen = pygame.display.set_mode(screen_size)
    pygame.display.set_caption("贪吃蛇")  # 设置窗口名称
    clock = pygame.time.Clock()  # 设置游戏的帧数
    isDead = False  # 初始化游戏没有结束
    score = 0  # 初始化分数
    # 3.创建一条蛇和食物
    snake = Snake()
    food = Food()
    # 4.启动游戏事件循环
    while True:
        # 循环监听事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()  # 手动关闭，事件结束
            if event.type == pygame.KEYDOWN:  # 检测到键盘按下
                if event.key == pygame.K_SPACE and isDead:  # 检测到按下空格，且蛇已经死亡，那么重新开始游戏
                    return main()
                snake.changeDirction(event.key)  # 否则改变蛇的运动方向
        screen.fill((255, 255, 255))  # 填充背景颜色
        # 绘制蛇的颜色
        for index, rect in enumerate(snake.body):
            if index == 0:
                # 画蛇头
                pygame.draw.rect(screen, (227, 29, 18), rect, 0)
                continue
            pygame.draw.rect(screen, (20, 220, 39), rect, 0)
        # 绘制食物,食物不能放在蛇的身体上 
        food.set()
        pygame.draw.rect(screen, (136, 0, 24), food.rect)
        # 碰撞检测
        if food.rect == snake.body[0]:
            score += 5
            snake.addNode()
            food.remove()
        # 绘制分数
        show_text(screen, (50, 500), "Scores："+str(score), (223, 223, 223), False, 100)
        # 死亡判别
        isDead = snake.isDead()
        if not isDead:
            # 没有死亡，继续移动
            snake.move()
        else:
            # 绘制死亡时的文字样式
            show_text(screen, (100, 200), "YOU DEAD", (227, 29, 18), False, 100)
            show_text(screen, (150, 260), "press space to try again...", (0, 0, 22), False, 30)
        # 绘制更新
        pygame.display.update()
        # 设置了画面更新的最大帧数
        clock.tick(10)


if __name__ == '__main__':
    main()
    